﻿using UnityEngine;
using UnityEngine.SceneManagement;

namespace TinyAsset
{
    public abstract class AssetLoader : BaseLoader<AssetLoader>
    {
        enum AssetAccess
        {
            Asset,

            Scene,
        }

        public abstract Object asset { get; protected set; }

        public abstract Scene scene { get; protected set; }

        protected abstract AsyncOperation asyncSceneOperation { get; set; }

        public bool allowSceneActivation
        {
            get
            {
                if (asyncSceneOperation == null)
                    return _allowSceneActivation;
                return asyncSceneOperation.allowSceneActivation;
            }
            set
            {
                if (asyncSceneOperation != null)
                    asyncSceneOperation.allowSceneActivation = value;
                _allowSceneActivation = value;
            }
        }

        string assetName;

        System.Type assetType;

        bool _allowSceneActivation = true;

        LoadSceneParameters loadSceneParameters;

        AssetAccess assetAccess;

        public AssetLoader(string assetPath, string assetName, System.Type assetType):base(assetPath)
        {
            this.assetName = assetName;
            this.assetType = assetType;
            this.assetAccess = AssetAccess.Asset;
        }

        public AssetLoader(string assetPath, string assetName, bool additive):base(assetPath)
        {
            this.assetName = assetName;
            this.loadSceneParameters = new LoadSceneParameters(additive ? LoadSceneMode.Additive : LoadSceneMode.Single);
            this.assetAccess = AssetAccess.Scene;
        }

        public override void Unload()
        {
            switch (assetAccess)
            {
                case AssetAccess.Asset:
                    UnloadAsset();
                    break;
                case AssetAccess.Scene:
                    UnloadScene();
                    break;
                default:
                    break;
            }
        }

        protected void UnloadAsset()
        {
            if (asset is GameObject)
                return;
            Resources.UnloadAsset(asset);
        }

        protected void UnloadScene()
        {
            if (scene.IsValid() && loadSceneParameters.loadSceneMode == LoadSceneMode.Additive)
                SceneManager.UnloadSceneAsync(scene);
        }

        protected abstract void SyncSceneLoadHandler(string assetName, LoadSceneParameters parameters);

        protected abstract void SyncAssetLoadHandler(string assetName, System.Type assetType);

        protected abstract void AsyncSceneLoadHandler(string assetName, LoadSceneParameters parameters);

        protected abstract void AsyncAssetLoadHandler(string assetName, System.Type assetType);

        protected override void SyncLoadHandler()
        {
            if (IsCompleted)
                return;

            switch (assetAccess)
            {
                case AssetAccess.Asset:
                    SyncAssetLoadHandler(assetName, assetType);
                    break;
                case AssetAccess.Scene:
                    SyncSceneLoadHandler(assetName, loadSceneParameters);
                    break;
            }
        }

        protected override void AsyncLoadHandler()
        {
            if (IsCompleted)
                return;

            switch (assetAccess)
            {
                case AssetAccess.Asset:
                    AsyncAssetLoadHandler(assetName, assetType);
                    break;
                case AssetAccess.Scene:
                    AsyncSceneLoadHandler(assetName, loadSceneParameters);
                    break;
            }
        }

        public AssetOperationHandle CreateAssetOperationHandle()
        {
            return new AssetOperationHandle(this);
        }
    }
}